package spring;

import spring.annotation.*;

import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;

/**
 * @ProjectName: Spring
 * @Package: spring
 * @ClassName: ConfigurationClassPostProcessor
 * @Author: zxh
 * @Description: 用于顶级注解的处理
 * @Date: 2022/3/10 20:40
 * @Version: 1.0
 */
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        // 这里按理说，应该是五个注解
        // FullyConfiguration 用了@Configuration注解的
        // LiteConfiguration 用了@Component、@ComponentScan、@Import、@ImportResource注解的

        // 先注册@ComponetScan
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) registry;
        processConfigBeanDefinitions(beanFactory);

        // 注册@Import 没有实现ImportSelector
        processImports(beanFactory);
    }

    private void processImports(DefaultListableBeanFactory registry) {
        String[] candidateNames = registry.getBeanDefinitionNames();
        for (String candidateName : candidateNames) {

            BeanDefinition bd = registry.getBeanDefinition(candidateName);
            Class appConfig = bd.getClazz();
            if(appConfig.isAnnotationPresent(Import.class)){
                Import annotation = (Import)appConfig.getDeclaredAnnotation(Import.class);
                Class<?>[] value = annotation.value();
                for (Class<?> aClass : value) {
                    String beanName = AnnotationBeanNameGenerator.buildDefaultBeanName(aClass);
                    registry.registerBeanDefinition(beanName,new BeanDefinition(aClass,"singleton"));
                }
            }
            if(appConfig.isAnnotationPresent(EnableAspectJAutoProxy.class)){
                EnableAspectJAutoProxy enableAspectJAutoProxy = (EnableAspectJAutoProxy)appConfig.getDeclaredAnnotation(EnableAspectJAutoProxy.class);
                String beanName = "aspectJAutoProxyRegistrar";
                registry.registerBeanDefinition(beanName,new BeanDefinition(AspectJAutoProxyRegistrar.class,"singleton"));
            }
        }
    }

    @Override
    public void postProcessBeanFactory(DefaultListableBeanFactory beanFactory) {
        // 此处应该是利用CGLIB对FullConfiguration注解进行代理，有点复杂，就当实现了，有空一定完善
    }

    private void processConfigBeanDefinitions(DefaultListableBeanFactory registry) {
        String[] candidateNames = registry.getBeanDefinitionNames();
        for (String candidateName : candidateNames) {

            BeanDefinition bd = registry.getBeanDefinition(candidateName);
            Class appConfig = bd.getClazz();
            if (appConfig.isAnnotationPresent(ComponentScan.class)) {
                ComponentScan componentScan = (ComponentScan) appConfig.getDeclaredAnnotation(ComponentScan.class);
                String path = componentScan.value();
                path = path.replace(".", "/");
                ClassLoader classLoader = registry.getLoader();
                URL resource = classLoader.getResource(path);
                File file = new File(resource.getFile());
                if (file.isDirectory()) {
                    File[] files = file.listFiles();
                    for (File f : files) {
                        /*D:\Javacode\Spring\target\classes\zhaoxiaohan\service\OrderService.class*/
                        String fileName = f.getAbsolutePath();
                        String className = fileName.substring(fileName.indexOf("zhaoxiaohan"), fileName.indexOf(".class"));
                        className = className.replace("\\", ".");
                        /*zhaoxiaohan.service.UserService*/
                        try {
                            Class<?> clazz = classLoader.loadClass(className);
                            String beanName = AnnotationBeanNameGenerator.buildDefaultBeanName(clazz);
                            BeanDefinition beanDefinition = new BeanDefinition();
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                Scope scope = clazz.getDeclaredAnnotation(Scope.class);
                                beanDefinition.setScope(scope.value());
                            } else {
                                // 默认创建单实例对象
                                beanDefinition.setScope("singleton");
                            }
                            beanDefinition.setClazz(clazz);
                            registry.registerBeanDefinition(beanName, beanDefinition);
                        } catch (Exception e) {
                            // System.err.println("错误的类名" + className);
                        }

                    }
                }
            }
        }
    }
}
